﻿using System;
using System.Threading.Tasks;
using Devonline.Core;
using Devonline.Entity;
using Devonline.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Logging;

namespace Devonline.MessageCenter
{
    public class MessageHub : Hub<IChannelClient>
    {
        private const string clientId = "clientId";
        private readonly ILogger<MessageHub> _logger;
        private readonly HttpContext _httpContext;
        private readonly IDistributedCache _cache;

        public MessageHub(ILogger<MessageHub> logger,
            HttpContext httpContext,
            IDistributedCache cache)
        {
            _logger = logger;
            _httpContext = httpContext;
            _cache = cache;
        }

        public override async Task OnConnectedAsync()
        {
            var userId = _httpContext.GetContextOption<string>(clientId);
            if (string.IsNullOrWhiteSpace(userId))
            {
                _logger.LogError("there has no user in client connection!");
                return;
            }

            _logger.LogInformation("{User} now connect the message center", userId);

            await Groups.AddToGroupAsync(Context.ConnectionId, userId);
            await base.OnConnectedAsync();
        }

        public override async Task OnDisconnectedAsync(Exception exception)
        {
            var userId = _httpContext.GetContextOption<string>(clientId);
            if (string.IsNullOrWhiteSpace(userId))
            {
                _logger.LogError("there has no user in client connection!");
                return;
            }

            _logger.LogInformation("{User} now connect the message center", userId);

            await Groups.RemoveFromGroupAsync(Context.ConnectionId, userId);
            await base.OnDisconnectedAsync(exception);
        }

        public async Task Send(Message message)
        {
            try
            {
                if (message.Receiver.IsNullOrEmpty())
                {
                    throw new Exception("The message has no receiver!");
                }

                if (message.Content == null)
                {
                    throw new Exception("The message has no content!");
                }

                //填充消息编号和消息当前连接
                message.Id ??= KeyGenerator.GetKey().ToString();

                //将收到的消息先保存到缓存中
                var content = message.ToJsonString();
                _logger.LogInformation("IM Server receive the {messageType} message {message} from {sender} to {receiver} at {time}", message.Type, content, message.Sender, message.Receiver, DateTime.Now);
                var messageKey = AppSettings.CACHE_USER + message.Sender + AppSettings.CHAR_UNDERLINE + message.Id;
                await _cache.SetStringAsync(messageKey, content);

                //发送消息到接收者
                await Clients.Group(message.Receiver).Receive(message);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Send message throw exception!");
            }
        }
    }
}
